/* 3DGo Game
 * Copyright (C) 2008 Roman Hwang, Eugene Melnichek

 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation - version 2
 * of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

/****************************************
Revision History

1.01 2008-03-09 Eugene Melnichek
Set maximum anisotropy to 4

1.00 Roman Hwang
Initial revision
****************************************/

#include "Board.h"

#include "GTPInterface.h"
#include "Logger.h"

#include <cassert>

using d3d::Vertex;

//////////////////////////////////////////////////////////////////////////


Board::Board(int _boardSize ): m_boardSize(_boardSize), m_stones(_boardSize*_boardSize), m_stoneNum(0)
{
	assert(_boardSize >= 5 && _boardSize <= 19);

}


//////////////////////////////////////////////////////////////////////////


void Board::Init()
{

	pMyDevice->CreateVertexBuffer(sizeof(Vertex)*8, D3DUSAGE_WRITEONLY,
								  Vertex::FVF, D3DPOOL_MANAGED,
								  &m_pBuffer, NULL);

	Vertex* v;
	m_pBuffer->Lock(0, 0, (void**)&v, 0);

	v[0] = Vertex(-10.0f, 10.0f, -1.0f, -0.33f, 0.33f, -0.33f, 0.0f, 0.0f);
	v[1] = Vertex( 10.0f, 10.0f, -1.0f,  0.33f, 0.33f, -0.33f, 1.0f, 0.0f);
	v[2] = Vertex( 10.0f,-10.0f, -1.0f,  0.33f,-0.33f, -0.33f, 1.0f, 1.0f);
	v[3] = Vertex(-10.0f,-10.0f, -1.0f, -0.33f,-0.33f, -0.33f, 0.0f, 1.0f);
	v[4] = Vertex(-10.0f, 10.0f,  1.0f, -0.33f, 0.33f,  0.33f, 0.0f, 0.0f);
	v[5] = Vertex( 10.0f, 10.0f,  1.0f,  0.33f, 0.33f,  0.33f, 1.0f, 0.0f);
	v[6] = Vertex( 10.0f,-10.0f,  1.0f,  0.33f,-0.33f,  0.33f, 1.0f, 1.0f);
	v[7] = Vertex(-10.0f,-10.0f,  1.0f, -0.33f,-0.33f,  0.33f, 0.0f, 1.0f);

	m_pBuffer->Unlock();

	pMyDevice->CreateIndexBuffer(sizeof(WORD) * 36, D3DUSAGE_WRITEONLY,
								 D3DFMT_INDEX16, D3DPOOL_MANAGED,
								 &m_pIndexBuffer, NULL);

	WORD* in;
	m_pIndexBuffer->Lock(0, 0, (void**)&in, 0);

	// front
	in[0] = 0; in[1] = 1; in[2] = 3;
	in[3] = 3; in[4] = 1; in[5] = 2;

	// right
	in[6] = 1; in[7] = 5; in[8] = 2;
	in[9] = 2; in[10] = 5; in[11] = 6;

	// left
	in[12] = 4; in[13] = 0; in[14] = 7;
	in[15] = 7; in[16] = 0; in[17] = 3;

	// back
	in[18] = 5; in[19] = 4; in[20] = 6;
	in[21] = 6; in[22] = 4; in[23] = 7;

	// up
	in[24] = 4; in[25] = 5; in[26] = 0;
	in[27] = 0; in[28] = 5; in[29] = 1;

	// bottom
	in[30] = 3; in[31] = 2; in[32] = 7;
	in[33] = 7; in[34] = 2; in[35] = 6;
	
	m_material = d3d::YELLOW_MTRL;

	// Init texture
	D3DXCreateTextureFromFile(pMyDevice, "board.bmp", &m_faceTexture);
	D3DXCreateTextureFromFile(pMyDevice, "boardback.bmp", &m_backTexture);

	// Turn on anisotropic texture filtering
	pMyDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
	pMyDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
	pMyDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ANISOTROPIC);
	pMyDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, 4);

	Stone::Init();
}


//////////////////////////////////////////////////////////////////////////
//CRITICAL_SECTION sc;

void Board::Reload()
{
	CRITICAL_SECTION sc;
	::InitializeCriticalSection(&sc);
	std::string& board = GTPInterface::GetInstance()->GetBoard();
	::EnterCriticalSection(&sc);
	Parse(board);
	::LeaveCriticalSection(&sc);
	::DeleteCriticalSection(&sc);
}


//////////////////////////////////////////////////////////////////////////


void Board::Clear()
{
	m_stones.clear();
}


//////////////////////////////////////////////////////////////////////////


void Board::Render()
{
	// Move board so it's z-coordinate is 0.
	D3DXMATRIX move;
	D3DXMatrixTranslation(&move, 0.0f, 0.0f, 1.0f);
	D3DXMATRIX scale;
	D3DXMatrixScaling(&scale, 0.35f, 0.35f, 0.35f);
	D3DXMATRIX mat;
	D3DXMatrixIdentity(&mat);
	D3DXMATRIX world = move * mat * scale;
	pMyDevice->SetTransform(D3DTS_WORLD, &world);
	pMyDevice->SetStreamSource(0, m_pBuffer, 0, sizeof(Vertex));
	pMyDevice->SetIndices(m_pIndexBuffer);
	pMyDevice->SetFVF(Vertex::FVF);
	pMyDevice->SetMaterial(&m_material);
	pMyDevice->SetTexture(0, m_faceTexture);
	pMyDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 2);
	pMyDevice->SetTexture(0, m_backTexture);
	pMyDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 6, 10);

	for(int i = 0; i < m_stoneNum; i++)
	{
		m_stones[i].Render();
	}
}

//////////////////////////////////////////////////////////////////////////


void Board::Parse(const std::string& _board)
{
	assert(_board.length() == m_boardSize*m_boardSize);

	// Clear board
	//Clear();

	m_stoneNum = 0;
	int counter = 0;
	for (int i = 0; i < m_boardSize; ++i)
	{
		for(int j = 0; j < m_boardSize; ++j, ++counter)
		{
			switch(_board[counter])
			{
			case CT_EMPTY:
			case CT_HANDICAP_SPOT:
				continue;
			case CT_WHITE:
				m_stones[m_stoneNum++].Set(i, j, WHITE);
				continue;
			case CT_BLACK:
				m_stones[m_stoneNum++].Set(i, j, BLACK);
				continue;
			}
		}
	}

#ifdef _DEBUG
	Logger::GetStream() << "Dumping stones: \n";
	for(int i = 0; i < counter; ++i)
	{
		Logger::GetStream() << i << " i= "<< m_stones[i].GetI() << " j=" 
			<< m_stones[i].GetJ() << " color=" << m_stones[i].GetColor() << std::endl;
	}
	Logger::GetStream() << "Dumping complete.\n";
#endif
}


//////////////////////////////////////////////////////////////////////////
